package com.example.ruoyivoicecall.common;

import com.example.ruoyivoicecall.entity.ExtActionInfoEntity;
import com.example.ruoyivoicecall.entity.ExtFlowInfoEntity;
import com.example.ruoyivoicecall.entity.VoiceInfoEntity;
import com.example.ruoyivoicecall.entity.NvrFlowActionInfoEntity;
import com.example.ruoyivoicecall.entity.NvrFlowInfoEntity;
import com.example.ruoyivoicecall.util.FileCommon;
import com.example.ruoyivoicecall.util.PathUtil;
import com.example.ruoyivoicecall.util.comm;
import com.example.ruoyivoicecall.util.FileDownloadAndUpload;
import com.example.ruoyivoicecall.util.NvrUtil;
import com.example.ruoyivoicecall.util.SysConfigUtil;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.classic.methods.HttpUriRequest;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.core5.http.HttpEntity;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class VoiceUnitUtil {
    private String serverUrl = "";
    private String sessionid = "";
    
    public VoiceUnitUtil() {
        this.serverUrl = SysConfigUtil.getVoiceUnitUrl();
    }
    
    // 以下是原始代码的方法，更新了包引用和一些语法
    public List<ExtFlowInfoEntity> getAllDefinedFlowList() throws IOException, ParseException {
        List<ExtFlowInfoEntity> flowList = new ArrayList<>();
        CloseableHttpClient httpclient = doLogin();
        HttpGet httpget = new HttpGet(this.serverUrl + "/v/vack?vo_id=v_flow_all&vtype=BPara&vflag=loadData&repType=ackjsp&ackjsp=/jsp/v_flow_all.jsp");
        
        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();
            InputStream instreams = entity.getContent();
            String str = ConvertStreamToString(instreams);
            
            Document jsoup = Jsoup.parse(str, this.serverUrl);
            Elements flowListElement = jsoup.getElementsByAttributeValue("id", "flow_list");
            if (flowListElement != null && flowListElement.size() > 0) {
                Elements flowElements = flowListElement.get(0).getElementsByTag("tr");
                for (int i = 1; i < flowElements.size(); i++) {
                    Element flowElement = flowElements.get(i);
                    Elements tdElements = flowElement.getElementsByTag("td");
                    if (tdElements.size() >= 6) {
                        ExtFlowInfoEntity flow = new ExtFlowInfoEntity();
                        flow.setFlowKey(tdElements.get(0).text());
                        flow.setDescription(tdElements.get(1).text());
                        flow.setVoiceKey(tdElements.get(2).text());
                        flow.setPlayNum(Integer.parseInt(tdElements.get(3).text()));
                        flow.setTimeOut(Integer.parseInt(tdElements.get(4).text()));
                        
                        // 填充动作信息
                        fillFlowInfo(flow, httpclient);
                        flowList.add(flow);
                    }
                }
            }
        } finally {
            response.close();
        }
        return flowList;
    }
    
    private void fillFlowInfo(ExtFlowInfoEntity flow, CloseableHttpClient httpclient) throws IOException, ParseException {
        HttpGet httpget = new HttpGet(this.serverUrl + "/v/vack?vo_id=v_flow&vtype=BPara&vflag=loadData&repType=ackjsp&ackjsp=/jsp/v_flow.jsp&flow_id=" + flow.getFlowKey());
        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();
            InputStream instreams = entity.getContent();
            String str = ConvertStreamToString(instreams);
            
            List<ExtActionInfoEntity> actionList = new ArrayList<>();
            
            Document jsoup = Jsoup.parse(str, this.serverUrl);
            Elements actionElements = jsoup.getElementsByAttributeValueContaining("name", "input");
            for (int i = 0; i < actionElements.size(); i++) {
                Element inputElement = actionElements.get(i);
                if (inputElement.attr("name").equals("input" + i)) {
                    ExtActionInfoEntity action = new ExtActionInfoEntity();
                    action.setOrder(i);
                    action.setInput(inputElement.attr("value"));
                    
                    // 获取其他属性
                    Elements typeElement = jsoup.getElementsByAttributeValue("name", "type" + i);
                    if (typeElement.size() > 0) action.setType(typeElement.get(0).attr("value"));
                    
                    Elements targetElement = jsoup.getElementsByAttributeValue("name", "target" + i);
                    if (targetElement.size() > 0) action.setTarget(targetElement.get(0).attr("value"));
                    
                    Elements valueElement = jsoup.getElementsByAttributeValue("name", "value" + i);
                    if (valueElement.size() > 0) action.setValue(valueElement.get(0).attr("value"));
                    
                    actionList.add(action);
                }
            }
            
            flow.setActionList(actionList);
        } finally {
            response.close();
        }
    }
    
    public List<VoiceInfoEntity> getAllDefinedVoiceList() throws IOException, ParseException {
        List<VoiceInfoEntity> voiceList = new ArrayList<>();
        CloseableHttpClient httpclient = doLogin();
//        HttpGet httpget = new HttpGet(this.serverUrl + "/v/vack?vo_id=saveShIndex&vtype=BPara&vflag=loadData&repType=ackjsp&ackjsp=/jsp/v_voice.jsp");
        HttpGet httpget = new HttpGet(this.serverUrl + "/v/sh/wavfile.jsp?_pageID_="+new Date().getTime());
        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();
            InputStream instreams = entity.getContent();
            String str = ConvertStreamToString(instreams);
            
            Document jsoup = Jsoup.parse(str, this.serverUrl);
            Elements voiceListElement = jsoup.getElementsByAttributeValue("id", "voice_list");
            if (voiceListElement != null && voiceListElement.size() > 0) {
                Elements voiceElements = voiceListElement.get(0).getElementsByTag("tr");
                for (int i = 1; i < voiceElements.size(); i++) {
                    Element voiceElement = voiceElements.get(i);
                    Elements tdElements = voiceElement.getElementsByTag("td");
                    if (tdElements.size() >= 5) {
                        VoiceInfoEntity voice = new VoiceInfoEntity();
                        voice.setKey(tdElements.get(0).text());
                        voice.setFileName(tdElements.get(1).text());
                        voice.setDescription(tdElements.get(2).text());
                        voice.setMaxIndex(Integer.parseInt(tdElements.get(3).text()));
                        voiceList.add(voice);
                    }
                }
            }
        } finally {
            response.close();
        }
        return voiceList;
    }
    
    private CloseableHttpClient doLogin() throws IOException, ParseException {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet(this.serverUrl + "/v/logon");
        
        CloseableHttpResponse closeableHttpResponse = httpclient.execute(httpget);
        try {
            InputStream is = closeableHttpResponse.getEntity().getContent();
            if (closeableHttpResponse.getHeaders("Set-Cookie").length > 0) {
                this.sessionid = closeableHttpResponse.getHeaders("Set-Cookie")[0].getValue().substring(0, 
                        closeableHttpResponse.getHeaders("Set-Cookie")[0].getValue().indexOf(";"));
            }
            
            StringBuffer out = new StringBuffer();
            byte[] b = new byte[4096]; 
            int n;
            while ((n = is.read(b)) != -1) {
                out.append(new String(b, 0, n, StandardCharsets.UTF_8));
            }
            
            Document jsoup = Jsoup.parse(out.toString(), this.serverUrl);
            String sysId = "";
            String idArea = "";
            Elements ele_sysId = jsoup.getElementsByAttributeValue("name", "sysId");
            if (ele_sysId != null && ele_sysId.size() > 0) {
                sysId = ele_sysId.get(0).attr("value");
            }
            
            Elements ele_idArea = jsoup.getElementsByAttributeValue("name", "id_area");
            if (ele_idArea != null && ele_idArea.size() > 0) {
                idArea = ele_idArea.get(0).attr("value");
            }
            
            HttpPost httpost = new HttpPost(this.serverUrl + "/v/logon");
            List<NameValuePair> nvps = new ArrayList<>();
            nvps.add(new BasicNameValuePair("sysId", sysId));
            nvps.add(new BasicNameValuePair("id_area", idArea));
            nvps.add(new BasicNameValuePair("j_username", SysConfigUtil.getVoiceUnitUserName()));
            nvps.add(new BasicNameValuePair("j_password", SysConfigUtil.getVoiceUnitPassword()));
//            nvps.add(new BasicNameValuePair("btype", "logon"));
            nvps.add(new BasicNameValuePair("vo_id", "logon"));
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8);
            httpost.setEntity(formEntity);
            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded");
            
            closeableHttpResponse = httpclient.execute(httpost);
            if(closeableHttpResponse.getCode()==500){
                System.out.println("登录失败，系统错误，"+closeableHttpResponse.getEntity().getContent());
                throw new IOException("登录失败");
            }
            is = closeableHttpResponse.getEntity().getContent();
            if (closeableHttpResponse.getHeaders("Set-Cookie").length > 0) {
                this.sessionid = closeableHttpResponse.getHeaders("Set-Cookie")[0].getValue().substring(0, 
                        closeableHttpResponse.getHeaders("Set-Cookie")[0].getValue().indexOf(";"));
            }
            
            out = new StringBuffer();
            while ((n = is.read(b)) != -1) {
                out.append(new String(b, 0, n, StandardCharsets.UTF_8));
            }
            
            if (out.toString().indexOf("frameset") == -1) {
                System.out.println("登录失败，请检查用户名和密码");
                throw new IOException("登录失败");
            }
        } finally {
            closeableHttpResponse.close();
        }
        return httpclient;
    }



    public void updateVoice(VoiceInfoEntity vi) throws IOException, ParseException {
        String fileUrl = SysConfigUtil.getServerPath() + vi.getFileName();
        String[] sp = vi.getFileName().split("/");
        
        String localName = vi.getDistFileName();
        String distPath = PathUtil.getNewInterface().getWebRoot() + File.separator + SysConfigUtil.getFileUploadFolderName();
        if (FileDownloadAndUpload.downLoadFromUrl(fileUrl, localName, distPath).booleanValue()) {
            System.out.println("文件下载完成@" + distPath + File.separator + localName);
            
            FileCommon.copyFile(distPath + File.separator + localName, SysConfigUtil.getLocalVoiceSavePath() + File.separator + localName);
            
            refreshVoiceList();
        } else {
            System.out.println("文件下载失败");
        }
    }
    
    public void uploadVoice(VoiceInfoEntity vi, Integer maxIndex) throws IOException, ParseException {
        String fileUrl = SysConfigUtil.getServerPath() + "/" + SysConfigUtil.getServerFileDirName() + "/" + vi.getFileName();
        if (vi.getFileName().indexOf("/") != -1) {
            fileUrl = SysConfigUtil.getServerPath() + "/" + vi.getFileName();
        }
        String[] sp = vi.getFileName().split("/");
        String localName = sp[sp.length - 1];
        String distPath = PathUtil.getNewInterface().getWebRoot() + File.separator + SysConfigUtil.getFileUploadFolderName();
        if (FileDownloadAndUpload.downLoadFromUrl(fileUrl, localName, distPath).booleanValue()) {
            System.out.println("文件下载完成@" + distPath + File.separator + localName);
            
            System.out.println("开始文件上传@" + distPath + File.separator + localName);
            String uploadurl = this.serverUrl + "/v/vack?vo_id=saveShIndex&_idaction_=2d&vtype=BPara&repType=ackjsp&ackjsp=/sh/vfile.jsp";
            String uploadRtn = uploadVoiceFile(this.serverUrl, uploadurl, distPath + File.separator + localName, maxIndex, vi.getKey());
            if (uploadRtn.indexOf("错误") != -1) {
                System.out.println("文件上传失败");
            } else {
                System.out.println("文件上传成功");
            }
        } else {
            System.out.println("文件下载失败");
        }
    }
    
    public String uploadVoiceFile(String serverUrl, String uploadurl, String uploadFile, Integer maxIndex, String key) throws IOException, ParseException {
        String BOUNDARY = "----WebKitFormBoundary" + System.currentTimeMillis();
        String twoHyphens = "--";
        String end = "\r\n";
        
        URL url = new URL(uploadurl);
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
        httpURLConnection.setDoInput(true);
        httpURLConnection.setDoOutput(true);
        httpURLConnection.setUseCaches(false);
        httpURLConnection.setRequestMethod("POST");
        
        httpURLConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0");
        httpURLConnection.addRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        httpURLConnection.addRequestProperty("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
        httpURLConnection.addRequestProperty("Accept-Encoding", "gzip, deflate");
        httpURLConnection.addRequestProperty("Referer", serverUrl + "/v/sh/vfile.jsp");
        httpURLConnection.addRequestProperty("Connection", "keep-alive");
        httpURLConnection.addRequestProperty("Upgrade-Insecure-Requests", "1");
        httpURLConnection.addRequestProperty("Cookie", this.sessionid);
        
        httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
        httpURLConnection.setRequestProperty("Charset", "UTF-8");
        httpURLConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
        
        DataOutputStream ds = null;
        FileInputStream fis = null;
        try {
            ds = new DataOutputStream(httpURLConnection.getOutputStream());
            String filename = uploadFile.substring(uploadFile.lastIndexOf(File.separator) + 1);
            
            ds.writeBytes(twoHyphens + BOUNDARY + end);
            ds.writeBytes("Content-Disposition: form-data; name=\"vo_id\"" + end);
            ds.writeBytes(end);
            ds.writeBytes("saveShIndex" + end);
            
            ds.writeBytes(twoHyphens + BOUNDARY + end);
            ds.writeBytes("Content-Disposition: form-data; name=\"_idaction_\"" + end);
            ds.writeBytes(end);
            ds.writeBytes("2d" + end);
            
            ds.writeBytes(twoHyphens + BOUNDARY + end);
            ds.writeBytes("Content-Disposition: form-data; name=\"vtype\"" + end);
            ds.writeBytes(end);
            ds.writeBytes("BPara" + end);
            
            ds.writeBytes(twoHyphens + BOUNDARY + end);
            ds.writeBytes("Content-Disposition: form-data; name=\"repType\"" + end);
            ds.writeBytes(end);
            ds.writeBytes("ackjsp" + end);
            
            ds.writeBytes(twoHyphens + BOUNDARY + end);
            ds.writeBytes("Content-Disposition: form-data; name=\"ackjsp\"" + end);
            ds.writeBytes(end);
            ds.writeBytes("/sh/vfile.jsp" + end);
            
            ds.writeBytes(twoHyphens + BOUNDARY + end);
            ds.writeBytes("Content-Disposition: form-data; name=\"v_flag\"" + end);
            ds.writeBytes(end);
            ds.writeBytes("1" + end);
            
            ds.writeBytes(twoHyphens + BOUNDARY + end);
            ds.writeBytes("Content-Disposition: form-data; name=\"vo_id\"" + end);
            ds.writeBytes(end);
            ds.writeBytes("saveShIndex" + end);
            
            ds.writeBytes(twoHyphens + BOUNDARY + end);
            ds.writeBytes("Content-Disposition: form-data; name=\"vfile\"" + 
                    "; filename=\"" + filename + "\"" + end);
            ds.writeBytes("Content-Type: audio/x-wav" + end);
            ds.writeBytes(end);
            
            fis = new FileInputStream(uploadFile);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) != -1) {
                ds.write(buffer, 0, length);
            }
            ds.writeBytes(end);
            
            ds.writeBytes(twoHyphens + BOUNDARY + twoHyphens + end);
            ds.flush();
            
            int responseCode = httpURLConnection.getResponseCode();
            if (responseCode == 200) {
                InputStream is = httpURLConnection.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
                StringBuffer result = new StringBuffer();
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }
                return result.toString();
            } else {
                return "上传失败，响应码: " + responseCode;
            }
        } finally {
            if (fis != null) fis.close();
            if (ds != null) ds.close();
            httpURLConnection.disconnect();
        }
    }
    
    public void refreshVoiceList() throws IOException, ParseException {
        CloseableHttpClient httpclient = doLogin();
        HttpGet httpget = new HttpGet(this.serverUrl + "/v/vack?vo_id=refreshVoiceList&vtype=BPara&vflag=refresh&repType=ackjsp&ackjsp=/jsp/v_voice.jsp");
        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();
            InputStream instreams = entity.getContent();
            String str = ConvertStreamToString(instreams);
            System.out.println("刷新语音列表结果: " + str);
        } finally {
            response.close();
        }
    }
    
    public void addFlow(Map<String, NvrFlowInfoEntity> flowMap, Map<String, List<NvrFlowActionInfoEntity>> remoteActionMap) throws IOException, ParseException {
        CloseableHttpClient httpclient = doLogin();
        NvrFlowInfoEntity startFlowByWorking = null;
        NvrFlowInfoEntity startFlowByLife = null;
        if (flowMap.size() == 0) {
            return;
        }
        for (String key : flowMap.keySet()) {
            if (addSingleFlow(key, flowMap, httpclient).booleanValue()) {
                addOrUpdateFlowAction(key, flowMap, httpclient, remoteActionMap);
            }
            if (flowMap.get(key).getType().equals(NvrUtil.FLOW_TYPE_STARTBYWORKING)) {
                startFlowByWorking = flowMap.get(key);
            }
            if (flowMap.get(key).getType().equals(NvrUtil.FLOW_TYPE_STARTBYLIFE)) {
                startFlowByLife = flowMap.get(key);
            }
        }
        if (startFlowByWorking != null && startFlowByLife != null) {
            setStartFlowInfo(startFlowByWorking.getFlowKey(), startFlowByLife.getFlowKey(), httpclient);
        } else {
            System.out.println("没有设置启动流程(上班时间或下班时间)");
        }
    }
    
    public void updateFlow(Map<String, NvrFlowInfoEntity> flowMap, Map<String, List<NvrFlowActionInfoEntity>> remoteActionMap) throws IOException, ParseException {
        CloseableHttpClient httpclient = doLogin();
        if (flowMap.size() == 0) {
            return;
        }
        for (String key : flowMap.keySet()) {
            if (updateSingleFlow(key, flowMap, httpclient).booleanValue()) {
                addOrUpdateFlowAction(key, flowMap, httpclient, remoteActionMap);
            }
        }
    }
    
    public void setStartFlowInfo(String workingFlowKey, String lifeFlowKey) throws IOException, ParseException {
        setStartFlowInfo(workingFlowKey, lifeFlowKey, doLogin());
    }
    
    private void setStartFlowInfo(String workingFlowKey, String lifeFlowKey, CloseableHttpClient httpclient) throws IOException, ParseException {
        HttpPost httpost = new HttpPost(this.serverUrl + "/v/vack");
        List<NameValuePair> nvps = new ArrayList<>();
        nvps.add(new BasicNameValuePair("vo_id", "saveMainFlow"));
        nvps.add(new BasicNameValuePair("vtype", "BPara"));
        nvps.add(new BasicNameValuePair("vflag", "saveData"));
        nvps.add(new BasicNameValuePair("repType", "ackjsp"));
        nvps.add(new BasicNameValuePair("ackjsp", "/jsp/v_flow_all.jsp"));
        nvps.add(new BasicNameValuePair("if_reload", "true"));
        nvps.add(new BasicNameValuePair("_idaction", "21"));
        nvps.add(new BasicNameValuePair("callinFlow", workingFlowKey));
        nvps.add(new BasicNameValuePair("callinFlowNotWorktime", lifeFlowKey));
        nvps.add(new BasicNameValuePair("", ""));
        
        httpost.setEntity(new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8));
        httpost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0");
        httpost.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        httpost.addHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
        httpost.addHeader("Accept-Encoding", "gzip, deflate");
        httpost.addHeader("Referer", this.serverUrl + "/v/jsp/v_flow_all.jsp");
        httpost.addHeader("Connection", "keep-alive");
        httpost.addHeader("Cookie", this.sessionid);
        
        CloseableHttpResponse closeableHttpResponse = httpclient.execute(httpost);
        try {
            HttpEntity entity = closeableHttpResponse.getEntity();
            InputStream instreams = entity.getContent();
            String str = ConvertStreamToString(instreams);
            System.out.println("设置启动流程结果: " + str);
        } finally {
            closeableHttpResponse.close();
        }
    }
    
    private Boolean addSingleFlow(String key, Map<String, NvrFlowInfoEntity> flowMap, CloseableHttpClient httpclient) throws IOException, ParseException {
        HttpPost httpost = new HttpPost(this.serverUrl + "/v/vack");
        List<NameValuePair> nvps = new ArrayList<>();
        nvps.add(new BasicNameValuePair("vo_id", "saveFlow"));
        nvps.add(new BasicNameValuePair("vtype", "BPara"));
        nvps.add(new BasicNameValuePair("vflag", "saveData"));
        nvps.add(new BasicNameValuePair("repType", "ackjsp"));
        nvps.add(new BasicNameValuePair("ackjsp", "/jsp/v_flow.jsp"));
        nvps.add(new BasicNameValuePair("if_reload", "true"));
        nvps.add(new BasicNameValuePair("_idaction", "2d"));
        nvps.add(new BasicNameValuePair("flow_id", key));
        nvps.add(new BasicNameValuePair("desc", flowMap.get(key).getDescription()));
        nvps.add(new BasicNameValuePair("voice_id", flowMap.get(key).getVoiceKey()));
        nvps.add(new BasicNameValuePair("voice_times", String.valueOf(flowMap.get(key).getPlayNum())));
        nvps.add(new BasicNameValuePair("timeout", String.valueOf(flowMap.get(key).getTimeOut())));
        nvps.add(new BasicNameValuePair("busy_flow", flowMap.get(key).getBusyFlowKey()));
        nvps.add(new BasicNameValuePair("noanswer_flow", flowMap.get(key).getNoAnswerFlowKey()));
        
        httpost.setEntity(new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8));
        httpost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0");
        httpost.addHeader("Cookie", this.sessionid);
        
        CloseableHttpResponse closeableHttpResponse = httpclient.execute(httpost);
        try {
            HttpEntity entity = closeableHttpResponse.getEntity();
            InputStream instreams = entity.getContent();
            String str = ConvertStreamToString(instreams);
            if (str.indexOf("func_delVFlowAction") != -1) {
                return Boolean.TRUE;
            }
            System.out.println("流程添加失败@key=" + key);
            return Boolean.FALSE;
        } finally {
            closeableHttpResponse.close();
        }
    }
    
    private Boolean updateSingleFlow(String key, Map<String, NvrFlowInfoEntity> flowMap, CloseableHttpClient httpclient) throws IOException, ParseException {
        HttpPost httpost = new HttpPost(this.serverUrl + "/v/vack?vo_id=saveFlow&vtype=BPara&vflag=saveData&repType=ackjsp&ackjsp=/jsp/v_flow.jsp&if_reload=true&_idaction=2d&flow_id=" + key);
        List<NameValuePair> nvps = new ArrayList<>();
        nvps.add(new BasicNameValuePair("desc", flowMap.get(key).getDescription()));
        nvps.add(new BasicNameValuePair("voice_id", flowMap.get(key).getVoiceKey()));
        nvps.add(new BasicNameValuePair("voice_times", String.valueOf(flowMap.get(key).getPlayNum())));
        nvps.add(new BasicNameValuePair("timeout", String.valueOf(flowMap.get(key).getTimeOut())));
        nvps.add(new BasicNameValuePair("busy_flow", flowMap.get(key).getBusyFlowKey()));
        nvps.add(new BasicNameValuePair("noanswer_flow", flowMap.get(key).getNoAnswerFlowKey()));
        
        httpost.setEntity(new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8));
        httpost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0");
        httpost.addHeader("Cookie", this.sessionid);
        
        CloseableHttpResponse closeableHttpResponse = httpclient.execute(httpost);
        try {
            HttpEntity entity = closeableHttpResponse.getEntity();
            InputStream instreams = entity.getContent();
            String str = ConvertStreamToString(instreams);
            if (str.indexOf("func_delVFlowAction") != -1) {
                return Boolean.TRUE;
            }
            System.out.println("流程更新失败@key=" + key);
            return Boolean.FALSE;
        } finally {
            closeableHttpResponse.close();
        }
    }
    
    private Boolean addOrUpdateFlowAction(String key, Map<String, NvrFlowInfoEntity> flowMap, CloseableHttpClient httpclient, Map<String, List<NvrFlowActionInfoEntity>> remoteActionMap) throws IOException, ParseException {
        List<NvrFlowActionInfoEntity> actList = remoteActionMap.get(key);
        if (actList == null || actList.size() == 0) {
            return Boolean.TRUE;
        }
        
        HttpPost httpost = new HttpPost(this.serverUrl + "/v/vack");
        List<NameValuePair> nvps = new ArrayList<>();
        nvps.add(new BasicNameValuePair("vo_id", "saveFlowAction"));
        nvps.add(new BasicNameValuePair("vtype", "BPara"));
        nvps.add(new BasicNameValuePair("vflag", "saveData"));
        nvps.add(new BasicNameValuePair("repType", "ackjsp"));
        nvps.add(new BasicNameValuePair("ackjsp", "/jsp/v_flow.jsp"));
        nvps.add(new BasicNameValuePair("if_reload", "true"));
        nvps.add(new BasicNameValuePair("_idaction", "2d"));
        nvps.add(new BasicNameValuePair("flow_id", key));
        nvps.add(new BasicNameValuePair("desc", flowMap.get(key).getDescription()));
        nvps.add(new BasicNameValuePair("voice_id", flowMap.get(key).getVoiceKey()));
        nvps.add(new BasicNameValuePair("voice_times", String.valueOf(flowMap.get(key).getPlayNum())));
        nvps.add(new BasicNameValuePair("timeout", String.valueOf(flowMap.get(key).getTimeOut())));
        nvps.add(new BasicNameValuePair("busy_flow", flowMap.get(key).getBusyFlowKey()));
        nvps.add(new BasicNameValuePair("no_answer", ""));
        nvps.add(new BasicNameValuePair("comment", ""));
        nvps.add(new BasicNameValuePair("busy_flow_td", "遇忙或失败"));
        nvps.add(new BasicNameValuePair("noanswer_flow_td", "未接听未登录或成功"));
        
        int index = 0;
        for (NvrFlowActionInfoEntity act : actList) {
            String keyNum = getKeyNum(act.getKeyNum());
            Integer type = act.getExeType();
            String stype = "";
            String starget = "";
            
            if (type.equals(NvrUtil.SUBFLOW_EXETYPE_EXE)) {
                stype = "invoke";
                starget = "flow";
            } else if (type.equals(NvrUtil.SUBFLOW_EXETYPE_FORWARD)) {
                stype = "transfer";
                starget = "ch";
            } else if (type.equals(NvrUtil.SUBFLOW_EXETYPE_NOTEBOOK)) {
                stype = "invoke";
                starget = "func";
            }
            
            String value = act.getTargetValue();
            nvps.add(new BasicNameValuePair("input" + index, keyNum));
            nvps.add(new BasicNameValuePair("type" + index, stype));
            nvps.add(new BasicNameValuePair("target" + index, starget));
            nvps.add(new BasicNameValuePair("value" + index, value));
            nvps.add(new BasicNameValuePair("value" + index + "2", ""));
            nvps.add(new BasicNameValuePair("busy" + index, "忙处理流程A"));
            nvps.add(new BasicNameValuePair("no_answer" + index, "忙处理流程B"));
            nvps.add(new BasicNameValuePair("comment" + index, "备注"));
            index++;
        }
        
        httpost.setEntity(new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8));
        httpost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0");
        httpost.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        httpost.addHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
        httpost.addHeader("Accept-Encoding", "gzip, deflate");
        httpost.addHeader("Referer", this.serverUrl + "/v/jsp/v_flow.jsp?action=displayFlow&flow_id=testSampleFlow");
        httpost.addHeader("Connection", "keep-alive");
        httpost.addHeader("Cookie", this.sessionid);
        
        try (CloseableHttpResponse closeableHttpResponse = httpclient.execute(httpost)) {
            HttpEntity entity = closeableHttpResponse.getEntity();
            InputStream instreams = entity.getContent();
            String str = ConvertStreamToString(instreams);
            if (str.indexOf("func_delVFlowAction") != -1) {
                return Boolean.TRUE;
            }
        }
        System.out.println("流程动作添加失败@key=" + key);
        return Boolean.FALSE;
    }
    
    private String getKeyNum(String keyNum) {
        if (keyNum.toLowerCase().equals("l")) {
            return "*";
        }
        if (keyNum.toLowerCase().equals("r")) {
            return "#";
        }
        return keyNum;
    }
    
    // New method with charset parameter
    public static String convertStreamToString(InputStream is) throws IOException {
        return convertStreamToString(is, StandardCharsets.UTF_8);
    }
    
    public static String convertStreamToString(InputStream is, java.nio.charset.Charset charset) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, charset));
        StringBuilder sb = new StringBuilder();
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } finally {
            is.close();
        }
        return sb.toString();
    }
    
    // 兼容旧方法名
    public static String ConvertStreamToString(InputStream is) throws IOException {
        return convertStreamToString(is, StandardCharsets.UTF_8);
    }
}